/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.abm.jwebsite.servlet;

import java.io.File;
import java.io.IOException;
import java.util.TreeSet;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.abm.jwebsite.sitemap.SiteMap;
import org.abm.jwebsite.sitemap.SiteMapImpl;
import org.abm.jwebsite.utilities.Constants;
import static org.abm.jwebsite.utilities.Constants.CNST_KEY_CONTENT_DIRECTORY;
import static org.abm.jwebsite.utilities.Constants.CNST_NAVIGATION_ERROR_404;
import static org.abm.jwebsite.utilities.Constants.CNST_NAVIGATION_ERROR_500;
import static org.abm.jwebsite.utilities.Constants.CNST_PAGE_ID;
import static org.abm.jwebsite.utilities.Constants.CNST_REQUEST_NAME_SITEMAP;
import static org.abm.jwebsite.utilities.Constants.CNST_REQUEST_NAME_UTILS;
import org.abm.jwebsite.utilities.Utilities;

/**
 *
 * @author Saptarshi Debnath (saptarshi.devnath@gmail.com)
 */
public class ContentPrinter extends HttpServlet {

    private String contentDIR;
    private ServletContext context;
    private String error404HREF;
    private final TreeSet<String> resourceURICache = new TreeSet<>();
    private Utilities utils;
    private SiteMap sitemap;
    private String paramVaueContent;
    private String paramName;
    private String templateName;
    private Logger log;

    @Override
    public void init() throws ServletException {
        super.init();
    }

    private void lazyInit(HttpServletRequest request) {
        ////////////////////////////////////////////////////////////////////////
        // Lazy Initializer.                                                  //
        ////////////////////////////////////////////////////////////////////////

        this.utils = Utilities.INSTANCE;
        utils.init(request);
        this.sitemap = SiteMapImpl.INSTANCE;
        this.contentDIR = Utilities.INSTANCE.getProperty(CNST_KEY_CONTENT_DIRECTORY);
        this.context = this.getServletContext();
        this.error404HREF = SiteMapImpl.INSTANCE.getHREF(CNST_NAVIGATION_ERROR_404);
        this.paramVaueContent = utils.getProperty(Constants.CNST_AJAX_PARAM_VALUE_CONTENT);
        this.paramName = utils.getProperty(Constants.CNST_AJAX_PARAM_NAME);
        this.templateName = this.contentDIR + utils.getProperty(Constants.CNST_AJAX_PAGE_TEMPLATE_NAME) + ".jsp";
        this.log = Logger.getLogger(this.getClass().getCanonicalName());
    }

    private String setRequestAttributes(HttpServletRequest request) {
        if (this.utils == null || this.sitemap == null) {
            this.lazyInit(request);
        }
        ////////////////////////////////////////////////////////////////////////
        // Intercept each and every request and set the value in the request. //
        ////////////////////////////////////////////////////////////////////////
        request.setAttribute(CNST_REQUEST_NAME_UTILS, this.utils);
        request.setAttribute(CNST_REQUEST_NAME_SITEMAP, this.sitemap);

        //
        // Detect and set the page id by scanning the requested URI for
        // request which matches. And later forward the request accordingly
        //
        String pageIDGenerated = sitemap.getpageIDByHREF(request.getRequestURI());
        if (pageIDGenerated != null) {
            request.setAttribute(CNST_PAGE_ID, pageIDGenerated);
        }
        return pageIDGenerated;
    }

    protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String dispatchedURI = null;
        String pageID = this.setRequestAttributes(request);
        boolean isContentRequested = request.getParameter(this.paramName) != null ? request.getParameter(this.paramName).trim().equalsIgnoreCase(this.paramVaueContent) : false;
        try {
            //
            // Step 1 : CHeck if the resource exists or not as the list of the conten
            // Condition : Page ID should be determined.
            //
            if (pageID != null && pageID.length() > 0) {
                //
                // Great we have found the page-id lets check if the file exist in the system or not
                //
                dispatchedURI = this.utils.getResourcePathByPageID(pageID);
                if (!isResourcePresent(dispatchedURI)) {
                    pageID = this.set404Page(request,response);
                }
            } else if (!this.isResourcePresent(request.getRequestURI())) {
                pageID = this.set404Page(request,response);
            }

            if (!isContentRequested && pageID != null) {
                //
                // template not loaded yet. Lets send the template.
                //
                dispatchedURI = this.templateName;
            } else if (pageID != null && isContentRequested) {
                //
                // Send the content of the determined page id
                //
                dispatchedURI = this.utils.getResourcePathByPageID(pageID);
            }
        } catch (Exception e) {
            log.log(Level.SEVERE, e.getMessage(), e);
            dispatchedURI = this.utils.getResourcePathByPageID(this.set500Page(request,response));
        } finally {
            if (dispatchedURI != null) {
                request.getRequestDispatcher(dispatchedURI).forward(request, response);
            }
        }
    }

    private String set500Page(HttpServletRequest request, HttpServletResponse response) throws IOException {
    	response.sendError(HttpServletResponse.SC_NOT_FOUND);
        request.setAttribute(CNST_PAGE_ID, CNST_NAVIGATION_ERROR_500);
        return CNST_NAVIGATION_ERROR_500;
    }

    private String set404Page(HttpServletRequest request, HttpServletResponse response) throws IOException {
    	response.sendError(HttpServletResponse.SC_NOT_FOUND);
        request.setAttribute(CNST_PAGE_ID, CNST_NAVIGATION_ERROR_404);
        return CNST_NAVIGATION_ERROR_404;
    }

    private boolean isResourcePresent(String URI) {
        boolean isExisting = this.resourceURICache.contains(URI) ? true : new File(this.context.getRealPath(URI)).exists();
        if (isExisting) {
            //
            // Caches the information if the uri exists. No caching for 404 request
            //
            synchronized (this.resourceURICache) {
                this.resourceURICache.add(URI);
            }
        }
        return isExisting;
    }

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }
}
